suppressPackageStartupMessages({
library(knitr)
library(tidyverse)
library(Seurat)
library(SeuratData)
library(scater)
library(zellkonverter)
library(SingleCellExperiment)
library(EnsDb.Mmusculus.v79)
library(Signac)
})
## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

## Warning in if (is.na(desc)) {: the condition has length > 1 and only the first
## element will be used

Mouse gastrulation days E7.5, E8.0, E8.5, E8.75

The dataset consists of multiome data (scATAC-seq & scRNA-seq) from cells at the four mentioned timepoints.

We can read in the .h5ad file as a SummarizedCellExperiment

rna_gastr_SE <- readH5AD("jupyter_notebooks/anndata_rna.h5ad")
atac_gastr_SE <- readH5AD("jupyter_notebooks/anndata_atac_peak_matrix.h5ad")

print(paste0("The RNA data has dimensions ", paste(dim(rna_gastr_SE), collapse = ", ")))
## [1] "The RNA data has dimensions 32285, 45991"
print(paste0("The ATAC data has dimensions ", paste(dim(atac_gastr_SE), collapse = ", ")))
## [1] "The ATAC data has dimensions 180499, 45991"

We can convert SummarizedCellExperiment to a Seurat object. The SummarizedExperiment contains the raw counts of the gene expression. Additionally we can add the metadata information to the Seurat objects.

rna_seurat <- as.Seurat(rna_gastr_SE, counts = "X", data = "X")
atac_seurat <- as.Seurat(atac_gastr_SE, counts = "X", data = "X")

# Lets add the metadata to the Seurat object
rna_seurat <- AddMetaData(rna_seurat, as.data.frame(colData(rna_gastr_SE)))
atac_seurat <- AddMetaData(atac_seurat, as.data.frame(colData(atac_gastr_SE)))
rna_seurat <- AddMetaData(rna_seurat, atac_seurat@meta.data %>% dplyr::select(BlacklistRatio:FRIP))


rna_seurat@meta.data %>% head %>% knitr::kable()
orig.ident nCount_originalexp nFeature_originalexp sample stage nFeature_RNA mitochondrial_percent_RNA ribosomal_percent_RNA celltype BlacklistRatio nDiFrags nFrags nMonoFrags nMultiFrags NucleosomeRatio PassQC PromoterRatio ReadsInBlacklist ReadsInPromoter ReadsInTSS Sample TSSEnrichment barcode nCount_RNA pass_rnaQC doublet_score doublet_call celltype.mapped_mnn celltype.score_mnn closest.cell celltype.mapped_seurat celltype.score_seurat TSSEnrichment_atac ReadsInTSS_atac PromoterRatio_atac NucleosomeRatio_atac nFrags_atac BlacklistRatio_atac ReadsInPeaks FRIP
E7.5_rep1#AAACAGCCAGGAACTG-1 E7.5 3268 1636 E7.5_rep1 E7.5 1636 22.55 6.55 Primitive_Streak 0.0245961 9409 26061 11164 5488 1.334378 1 0.1753770 1282 9141 2170 E7.5_rep1 12.277 AAACAGCCAGGAACTG-1 3268 TRUE 0.05 FALSE Primitive_Streak 0.84 cell_114243 Epiblast 0.95 12.28 2170 0.18 1.33 26061 0.02 18291 0.3509267
E7.5_rep1#AAACAGCCATCCTGAA-1 E7.5 6034 2677 E7.5_rep1 E7.5 2677 21.63 6.36 Nascent_mesoderm 0.0131758 8183 22048 9047 4818 1.437051 1 0.1533246 581 6761 1596 E7.5_rep1 10.097 AAACAGCCATCCTGAA-1 6034 TRUE 0.11 FALSE Nascent_mesoderm 0.56 cell_87889 Nascent_mesoderm 0.53 10.10 1596 0.15 1.44 22048 0.01 17007 0.3857862
E7.5_rep1#AAACAGCCATGCTATG-1 E7.5 11993 3985 E7.5_rep1 E7.5 3985 24.96 8.14 Primitive_Streak 0.0168382 12809 37415 16731 7875 1.236268 1 0.1664038 1260 12452 2770 E7.5_rep1 9.157 AAACAGCCATGCTATG-1 11993 TRUE 0.52 FALSE Primitive_Streak 0.64 cell_103930 Rostral_neurectoderm 0.50 9.16 2770 0.17 1.24 37415 0.02 27761 0.3711364
E7.5_rep1#AAACATGCAACCTGGT-1 E7.5 11572 3703 E7.5_rep1 E7.5 3703 14.47 12.73 Parietal_endoderm 0.0451070 6366 13080 3807 2907 2.435776 1 0.2454128 1180 6420 1722 E7.5_rep1 17.397 AAACATGCAACCTGGT-1 11572 TRUE 0.52 FALSE Parietal_endoderm 1.00 cell_61845 Parietal_endoderm 1.00 17.40 1722 0.25 2.44 13080 0.05 10645 0.4071991
E7.5_rep1#AAACATGCAATGAATG-1 E7.5 10924 4030 E7.5_rep1 E7.5 4030 15.93 5.32 Somitic_mesoderm 0.0154294 8281 19411 6073 5057 2.196279 1 0.2148524 599 8341 2149 E7.5_rep1 16.820 AAACATGCAATGAATG-1 10924 TRUE 0.36 FALSE Somitic_mesoderm 0.84 cell_121109 Somitic_mesoderm 0.87 16.82 2149 0.21 2.20 19411 0.02 16046 0.4135354
E7.5_rep1#AAACATGCAATTATGC-1 E7.5 7175 3115 E7.5_rep1 E7.5 3115 18.16 7.01 Gut 0.0151415 3495 9114 3186 2433 1.860640 1 0.1916831 276 3494 827 E7.5_rep1 11.372 AAACATGCAATTATGC-1 7175 TRUE 0.10 FALSE Gut 0.88 cell_48964 Gut 1.00 11.37 827 0.19 1.86 9114 0.02 7385 0.4054573
atac_seurat@meta.data %>% head %>% knitr::kable()
orig.ident nCount_originalexp nFeature_originalexp BlacklistRatio nDiFrags nFrags nMonoFrags nMultiFrags NucleosomeRatio PassQC PromoterRatio ReadsInBlacklist ReadsInPromoter ReadsInTSS Sample TSSEnrichment barcode sample nFeature_RNA nCount_RNA mitochondrial_percent_RNA ribosomal_percent_RNA stage pass_rnaQC doublet_score doublet_call celltype.mapped_mnn celltype.score_mnn closest.cell celltype.mapped_seurat celltype.score_seurat TSSEnrichment_atac ReadsInTSS_atac PromoterRatio_atac NucleosomeRatio_atac nFrags_atac BlacklistRatio_atac ReadsInPeaks FRIP
E8.5_rep1#TTACGTTTCTGGCATG-1 E8.5 105065 46293 0.0175625 98930 221979 74921 48128 1.962841 1 0.1424189 7797 63228 15431 E8.5_rep1 10.457 TTACGTTTCTGGCATG-1 E8.5_rep1 6842 23641 0.79 2.94 E8.5 TRUE 0.85 FALSE ExE_endoderm 0.72 cell_90417 Visceral_endoderm 0.47 10.46 15431 0.14 1.96 221979 0.02 122008 0.2749303
E8.5_rep1#TCCTCTAAGTCCTTCA-1 E8.5 97181 42026 0.0153818 56865 150503 65362 28276 1.302607 1 0.1762855 4630 53063 13732 E8.5_rep1 12.839 TCCTCTAAGTCCTTCA-1 E8.5_rep1 4936 12218 0.46 2.83 E8.5 TRUE 0.43 FALSE ExE_mesoderm 0.92 cell_99030 ExE_mesoderm 0.74 12.84 13732 0.18 1.30 150503 0.02 110797 0.3681404
E8.5_rep1#TATCCAGCACAGACTC-1 E8.5 91323 37261 0.0186042 68122 150154 53887 28145 1.786461 1 0.1928220 5587 57906 15136 E8.5_rep1 14.320 TATCCAGCACAGACTC-1 E8.5_rep1 8194 56000 17.93 5.12 E8.5 TRUE 1.03 FALSE ExE_endoderm 1.00 cell_26080 ExE_endoderm 1.00 14.32 15136 0.19 1.79 150154 0.02 110569 0.3682810
E8.5_rep1#GAGAACCAGACACTTA-1 E8.5 98358 43749 0.0168635 62358 149079 57677 29044 1.584722 1 0.1802870 5028 53754 13554 E8.5_rep1 12.929 GAGAACCAGACACTTA-1 E8.5_rep1 3434 8178 23.05 7.65 E8.5 TRUE 0.61 FALSE ExE_endoderm 1.00 cell_82904 ExE_endoderm 1.00 12.93 13554 0.18 1.58 149079 0.02 110888 0.3719776
E8.5_rep1#TCAAGTATCTTAGCGG-1 E8.5 89709 38467 0.0168807 65453 136754 43825 27476 2.120456 1 0.2157962 4617 59022 14931 E8.5_rep1 13.170 TCAAGTATCTTAGCGG-1 E8.5_rep1 4867 12848 5.68 7.35 E8.5 TRUE 1.14 FALSE Erythroid1 0.80 cell_77053 Erythroid1 0.78 13.17 14931 0.22 2.12 136754 0.02 105227 0.3849027
E8.5_rep1#CCCTTAATCTCACAAA-1 E8.5 82843 37384 0.0158621 48689 122525 49548 24288 1.472855 1 0.1740788 3887 42658 10573 E8.5_rep1 11.612 CCCTTAATCTCACAAA-1 E8.5_rep1 5022 12406 3.83 4.32 E8.5 TRUE 1.00 FALSE Mesenchyme 0.96 cell_131042 Mesenchyme 0.55 11.61 10573 0.17 1.47 122525 0.02 91139 0.3719868

scRNA-seq

QC

Empty Droplets


tibble(sample = rna_seurat@meta.data$sample, umi_per_cell = Matrix::colSums(rna_seurat@assays$originalexp @counts)) %>% 
  arrange(sample, desc(umi_per_cell)) %>% 
  group_by(sample) %>% 
  mutate(idx = seq_along(sample)) %>% 
  mutate(cum_umi_per_cell = cumsum(umi_per_cell)) %>% 
  ggplot() +
  geom_line(aes(x = idx, y = cum_umi_per_cell)) +
  facet_wrap(~sample, scales = "fixed") +
  scale_y_log10() + scale_x_log10() +
  ylab("cumulative UMI count") +
  xlab("index")

From the plots below it seems that all cells with percentage of mitochondrial genes above 40% were removed. The early time points E7.5rep1/2 have the highest percentage of mitochondrial genes. Especially E7.5 rep2 seems to have a higher percentage of mitochondrial genes. Conversely, the same replicates from E7.5 have a lower number of features and counts. This means that the E7.5 rep2 and to a lesser extent E7.5 rep1 are of lower quality compared to the other samples. E8.75 rep1/rep2 seem to have the highest quality.

#rename metadata

variables <- c("nFeature_originalexp", "nCount_originalexp", "mitochondrial_percent_RNA", "ribosomal_percent_RNA")
plots <- map(variables, function(n){
  df <- rna_seurat@meta.data
  ggplot(df) +
    geom_boxplot(aes(x = df %>% pull("sample"), y = df %>% pull(n),
                     fill = df %>% pull("sample")), alpha = .1) +
    geom_violin(aes(x = df %>% pull("sample"), y = df %>% pull(n),
                     fill = df %>% pull("sample")), alpha = .5) +
    xlab("sample") +
    ylab(paste0(n)) +
    labs(title = paste0(n)) +
    guides(fill=guide_legend(title="sample"))
})

gridExtra::grid.arrange(grobs = plots, ncol = 2)

How good are the annotations?

There are two different methods for mapping listed in the metadata:

  • Seurat
  • MNN
atac_seurat@meta.data %>% group_by(celltype.mapped_seurat) %>% 
  summarise(n = n()) %>% knitr::kable(caption = "Number of celltypes using Seurat")
Number of celltypes using Seurat
celltype.mapped_seurat n
Allantois 735
Anterior_Primitive_Streak 86
Blood_progenitors_1 148
Blood_progenitors_2 526
Cardiomyocytes 895
Caudal_Mesoderm 240
Caudal_epiblast 643
Caudal_neurectoderm 54
Def._endoderm 301
Endothelium 651
Epiblast 976
Erythroid1 761
Erythroid2 508
Erythroid3 1096
ExE_ectoderm 3337
ExE_endoderm 6000
ExE_mesoderm 1434
Forebrain_Midbrain_Hindbrain 3588
Gut 2126
Haematoendothelial_progenitors 998
Intermediate_mesoderm 942
Mesenchyme 3201
Mixed_mesoderm 425
NMP 1699
Nascent_mesoderm 946
Neural_crest 529
Notochord 169
PGC 164
Paraxial_mesoderm 2161
Parietal_endoderm 528
Pharyngeal_mesoderm 1655
Primitive_Streak 316
Rostral_neurectoderm 1565
Somitic_mesoderm 1618
Spinal_cord 1527
Surface_ectoderm 2804
Visceral_endoderm 639

atac_seurat@meta.data %>% group_by(celltype.mapped_mnn) %>% 
  summarise(n = n()) %>% knitr::kable(caption = "Number of celltypes using MNN")
Number of celltypes using MNN
celltype.mapped_mnn n
Allantois 661
Anterior_Primitive_Streak 83
Blood_progenitors_1 258
Blood_progenitors_2 596
Cardiomyocytes 874
Caudal_Mesoderm 143
Caudal_epiblast 566
Caudal_neurectoderm 24
Def._endoderm 503
Endothelium 649
Epiblast 614
Erythroid1 1196
Erythroid2 887
Erythroid3 165
ExE_ectoderm 3360
ExE_endoderm 6226
ExE_mesoderm 1199
Forebrain_Midbrain_Hindbrain 3514
Gut 1895
Haematoendothelial_progenitors 992
Intermediate_mesoderm 840
Mesenchyme 3209
Mixed_mesoderm 230
NMP 1636
Nascent_mesoderm 1094
Neural_crest 526
Notochord 142
PGC 40
Paraxial_mesoderm 2398
Parietal_endoderm 541
Pharyngeal_mesoderm 1842
Primitive_Streak 333
Rostral_neurectoderm 1965
Somitic_mesoderm 1708
Spinal_cord 1673
Surface_ectoderm 2784
Visceral_endoderm 625

The annotations are similar across the different samples. However, there are some differences in the confidence with which cells can me mapped for different celltypes. For example, cardiomyocytes, erythroids and extraembryonic ectoderm and endoderm (but not mesoderm), mesenchyme and parietal endoderm can be mapped with very high confidence.

atac_seurat@meta.data %>% 
  ggplot() + 
  geom_boxplot(aes(x = celltype.mapped_seurat, y =  celltype.score_seurat, fill = celltype.mapped_seurat)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.8, hjust=1)) + NoLegend()



atac_seurat@meta.data %>% 
  ggplot() + 
  geom_boxplot(aes(x = celltype.mapped_mnn, y =  celltype.score_mnn, fill = celltype.mapped_mnn)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.8, hjust=1)) + NoLegend()

Normalize & Scale

rna_seurat <- rna_seurat %>% 
  NormalizeData(verbose = FALSE) %>% 
  ScaleData(verbose = FALSE) %>%
  FindVariableFeatures(verbose = FALSE)


#gastr_seurat@assays$RNA@data[0:10, 0:10]

PCA

I will proceed with 15 PCs.

rna_seurat <- RunPCA(rna_seurat, features = VariableFeatures(rna_seurat),
             verbose = FALSE)

ElbowPlot(rna_seurat)

pca_plots <- comprehenr::to_list(for (i in 1:15)
  DimPlot(rna_seurat, reduction = "pca", dims = i:(i+1)) +
    theme())

#pca_plots
#gridExtra::grid.arrange(unlist(pca_plots), ncol = 3, nrow = 5)

Clustering

Trying a different resolution for the clustering to see if the Mesenchyme will still separate.

rna_seurat <- FindNeighbors(rna_seurat, verbose = FALSE)
rna_seurat <- FindClusters(rna_seurat, verbose = FALSE, resolution = 0.6)
rna_seurat <- RunUMAP(rna_seurat, verbose = FALSE, dims = 1:15)
## Warning: The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
## To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
## This message will be shown once per session

Visualization

colPalette_celltypes = c('#532C8A',
 '#c19f70',
 '#f9decf',
 '#c9a997',
 '#B51D8D',
 '#3F84AA',
 '#9e6762',
 '#354E23',
 '#F397C0',
 '#ff891c',
 '#635547',
 '#C72228',
 '#f79083',
 '#EF4E22',
 '#989898',
 '#7F6874',
 '#8870ad',
 '#647a4f',
 '#EF5A9D',
 '#FBBE92',
 '#139992',
 '#cc7818',
 '#DFCDE4',
 '#8EC792',
 '#C594BF',
 '#C3C388',
 '#0F4A9C',
 '#FACB12',
 '#8DB5CE',
 '#1A1A1A',
 '#C9EBFB',
 '#DABE99',
 '#65A83E',
 '#005579',
 '#CDE088',
 '#f7f79e',
 '#F6BFCB')

There are two possibilities to proceed with celltype annotations:

  • Seurat (this is the one I used)
  • MNN

In the plot below you can see that the Mesenchyme separates into two clusters, even though the cells belong to the same celltype. Therefore I visualized the Mesenchyme cells according to their respective time point and replicate below. It becomes evident that the Mesenchyme separate into E7.5 and E8.0, E8.5, E8.75. Therefore, the separation is probably a biological effect corresponding to different signatures at different time points. However, we should keep in mind that E7.5 was also the time point with lowest quality of cells.

There is one cluster which contains a very heterogeneous population of cells, namely mixed & nascent mesoderm, caudal & rostral neuroectoderm, primitive streak, caudal epiblast and epiblast. As we will see later on, these are primarily early celltypes found at E7.5, which are not present at later timepoints anymore.

celltypes <- (atac_seurat@meta.data %>% group_by(celltype.mapped_seurat) %>% 
  summarise(n = n()))$celltype.mapped_seurat

col <- setNames(colPalette_celltypes, celltypes)
DimPlot(rna_seurat, reduction = "umap", pt.size = 1, 
        group.by = "celltype.mapped_seurat", label = TRUE, repel = TRUE, cols = col) +
  NoLegend()

DimPlot(subset(rna_seurat, celltype.mapped_seurat == "Mesenchyme"), 
        group.by = "sample")

DimPlot(subset(rna_seurat, celltype.mapped_seurat == "Mesenchyme"), 
        split.by  = "sample")

Plot with color legend.

DimPlot(rna_seurat, reduction = "umap", pt.size = 1, 
        group.by = "celltype.mapped_seurat", cols = col) #, label = TRUE, repel = TRUE) +

Clustering by Seurat with resolution = 0.6 yields 17 distinct clusters, not enough to differentiate the large number of different celltypes in this dataset.

DimPlot(rna_seurat, reduction = "umap", pt.size = .1, 
        group.by = "seurat_clusters", label = TRUE) +
  NoLegend()

Below, you can see how the earlier time points separate from the later time points. The number of counts is very homogenous, while the mitochondrial RNA percentage is higher and the number of features lower for E7.5 as already pointed out.

p1 <- DimPlot(rna_seurat, reduction = "umap", pt.size = .1, group.by = "sample")

p2 <- FeaturePlot(rna_seurat, reduction = "umap", pt.size = .1,
            features = "nCount_RNA") +
    scale_color_viridis_c() 
p3 <- FeaturePlot(rna_seurat, reduction = "umap", pt.size = .1, features = "mitochondrial_percent_RNA") +
    scale_color_viridis_c() 

p4 <- FeaturePlot(rna_seurat, reduction = "umap", pt.size = .1, features = "nFeature_RNA") +
    scale_color_viridis_c() 

gridExtra::grid.arrange(p1, p2, p3, p4, ncol = 2, nrow = 2)

Distribution of celltypes at different time points

Visualizing the cells at each timepoint in separate UMAPs shows how the distribution of celltypes changes as gastrulation proceeds. The heterogenous cell cluster present at E7.5 disappears at later time points. We can also see how no Erythroids are present at E7.5, Erythroid1 (and to lesser extend Erythroid2 and 3) appear at E8.0, while Eryhtroid3 are found to a higher extent at E8.75, which indicates that these cells correspond to different developmental stages.

DimPlot(rna_seurat, reduction = "umap", pt.size = 1, 
        group.by = "celltype.mapped_seurat", split.by = "orig.ident", ncol = 1, cols = col) +
  labs(title = "Celltypes at different time points")

We can see that nascent mesoderm, epiblast and primitive streak are only present at E75. Also, extraembryonice endoderm and ectoderm are highest and decrease with progressing gastrulation. Forebrain/Midbrain/Hindbrain, neural crest and neuromesodermal progenitor (NMP) cells are not present at E7.5, but emerge at E8.0 and are present at even higher percentage at E8.5. Also, the endothelium appears only at E8.0. The same is true for Allantois, erythroids (produce red blood cells, remain in bone marrow)and cardiomyocytes. Conversely, the number of extraembryonic ectoderm cells and extraembryonic endoderm cells become less at each time step.

(Pijuan_Sala et.al, A single-cell molecular map of mouse gastrulation and early organogenesis, 2019, Nature)

# plot the frequency of each cell type at each embryonic stage
# all frequencies for one embryonic stage would add up to 0
rna_seurat@meta.data %>%
  group_by(orig.ident, celltype.mapped_seurat) %>% 
  summarise(Total = n()) %>% 
  mutate(freq = Total/sum(Total)) %>% 
  ggplot(aes(x = celltype.mapped_seurat, y = freq, fill = orig.ident)) +
  geom_bar(position = "dodge", stat = "identity") +
  theme(axis.text.x = element_text(angle = 45, vjust = 0.8, hjust=1)) 

Processing Data at each time step separately

When doing the preprocessing steps and dimensionality reduction for each time point separately, we can create more clearly separated clusters for the later time points, however, for E7.5 the mixed cluster of epiblast, mixed & nascent mesoderm, primitive streak and PGC remains a heterogeneous cluster.

stages <- c("E7.5", "E8.0", "E8.5", "E8.75")
seurat_objects <- map(stages, function(n){
  rna_seurat <- subset(rna_seurat, subset = orig.ident == n)
  rna_seurat <- rna_seurat  %>% 
    NormalizeData(verbose = FALSE) %>% 
    ScaleData(verbose = FALSE) %>%
    FindVariableFeatures(verbose = FALSE) 
  rna_seurat <- rna_seurat %>%  RunPCA(features = VariableFeatures(rna_seurat), verbose = FALSE) %>% 
    FindNeighbors(verbose = FALSE) %>% 
    FindClusters(verbose = FALSE, resolution = .9) %>% 
    RunUMAP(verbose = TRUE, dims = 1:15)
  list(name = n, object = rna_seurat)
    
})


e75 <- seurat_objects[[1]]$object
e80 <- seurat_objects[[2]]$object
e85 <- seurat_objects[[3]]$object
e785 <- seurat_objects[[4]]$object
plots <- map(seq.int(1,4), function(n){
  object <- seurat_objects[[n]]$object
  p1 <- DimPlot(object, reduction = "umap", group.by = "celltype.mapped_seurat", 
                cols = col, size = .9) +
    labs(title = paste0(seurat_objects[[n]]$name, " celltypes"))
  list(plot = p1)
})

gridExtra::grid.arrange(plots[[1]]$p, plots[[2]]$p, plots[[3]]$p,plots[[4]]$p, ncol = 1)

scATAC-seq data

QC ATAC

atac_seurat@meta.data %>%
  ggplot() +
  geom_density2d_filled(aes(x=log10(nFrags_atac ), y=TSSEnrichment_atac), bins=20) +
  geom_hline(yintercept = 5, color="green", linetype="dashed") +
  geom_vline(xintercept = 3, color="green", linetype="dashed") +
  #geom_xsidedensity(aes(x=log10(pre_filter_meta$nFrags))) +
  #geom_ysidedensity(aes(y = pre_filter_meta$TSSEnrichment)) +
  facet_wrap(~sample) +
  theme(legend.position = "none") +
  labs(x = "Log10 Unique Fragments", y = "TSS Enrichment Score")

The scATAC-seq shows that E7.5 seems to be of lower quality, which we have already observed in the scRNA-seq. Potentially, the cells where simply in a worse condition when sequenced.

p1 <- atac_seurat@meta.data %>% 
  ggplot() +
  ggridges::geom_density_ridges(aes(x = TSSEnrichment, y = Sample, fill = Sample),
                                alpha = .6)

p2 <- atac_seurat@meta.data %>% 
  ggplot() +
  geom_violin(aes(x = Sample, y = TSSEnrichment, fill = Sample), alpha = 0.6) +
  geom_boxplot(aes(x = Sample, y = TSSEnrichment,fill = Sample), alpha = 0.1) + 
  theme(legend.position = "none") +
  labs(title = "TSS Enrichment")
cowplot::plot_grid(p2, p1, ncol = 2)

p1 <- atac_seurat@meta.data %>% 
  ggplot() +
  ggridges::geom_density_ridges(aes(x = nFrags_atac , y = Sample, fill = Sample),
                                alpha = .6)

p2 <- atac_seurat@meta.data %>% 
  ggplot() +
  geom_violin(aes(x = Sample, y = nFrags_atac , fill = Sample), alpha = 0.6) +
  geom_boxplot(aes(x = Sample, y = nFrags_atac ,fill = Sample), alpha = 0.1) + 
  theme(legend.position = "none") +
  labs(title = "TSS Enrichment")
cowplot::plot_grid(p2, p1, ncol = 2)

Normalization & Dimensionality reduction ATAC

Latent Semantic Indexing

  1. TF-IDF normalization
  • normalize across cells (sequencing depth)
  • normalize across peak (higher values to more rare peaks)
  1. Select Top features
  2. Run SVD on selected features
atac_seurat <- RunTFIDF(atac_seurat)
atac_seurat <- FindTopFeatures(atac_seurat)
atac_seurat <- RunSVD(atac_seurat)

The first LSI component often captures sequencing depth. We will therefore remove it from downstream analysis. The correlation between sequencing depth and each LSI component is shown in the plot below.

DepthCor(atac_seurat)

Visualization

atac_seurat <- RunUMAP(atac_seurat, reduction = "lsi", dims = 2:30, verbose = FALSE)
aatac_seurat <- FindNeighbors(atac_seurat, reduction = "lsi", dims = 2:30, verbose = FALSE)

# for Clsutering instead of Louvian SLM algorithm is used
#atac_seurat <- FindClusters(atac_seurat, verbose = FALSE, algorithm = 3) 

DimPlot(atac_seurat, group.by = "celltype.mapped_seurat", reduction = "umap", pt.size = 1, cols = col) +
  labs(title = "scATAC-seq Celltype")

  
DimPlot(atac_seurat, group.by = "sample", reduction = "umap", pt.size = 1, cols = col) +
  labs(title = "scATAC-seq Celltype")

DimPlot(rna_seurat , group.by = "celltype.mapped_seurat", pt.size = 1, cols = col,
        reduction = "umap") +
  labs(title = "scRNA-seq Celltype")

Lets have a look at whether the number of fragments is correlated to the number of counts in each celltype. This seems to be the case.

atac_seurat@meta.data %>% 
  ggplot(aes(x = log10(nCount_originalexp ), y = log10(nFrags_atac))) +
  geom_point(alpha = .2, size = .2) +
  ggside::geom_xsidedensity() +
  ggside::geom_ysidedensity() +
  facet_wrap(~sample) +
  labs(x = "Log10 Counts", y = "log10 Unique Fragments")

atac_seurat@meta.data %>% 
  ggplot(aes(x = log10(nCount_originalexp), y = log10(TSSEnrichment))) +
  geom_point(size = .2, alpha = .2) +
  ggside::geom_xsidedensity() +
  ggside::geom_ysidedensity() +
  facet_wrap(~sample)

atac_seurat@meta.data %>% 
  ggplot() +
  geom_histogram(aes(x = PromoterRatio_atac)) 


atac_seurat@meta.data %>% 
  ggplot() +
  geom_histogram(aes(x = NucleosomeRatio_atac)) 

saveRDS(atac_seurat, "atac_Seurat_object")
saveRDS(rna_seurat, "rna_Seurat_object")
LS0tCnRpdGxlOiAiUHJvY2Vzc2VkIHNjUk5BLXNlcSAmIHNjQVRBQy1zZXEgb2YgbW91c2UgZ2FzdHJ1bGF0aW9uIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBjb3NtbwogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQotLS0KCgo8c3R5bGU+CmJvZHkgewp0ZXh0LWFsaWduOiBqdXN0aWZ5fQo8L3N0eWxlPgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IEZBTFNFLCBhdXRvZGVwID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSkKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YS8iKQpzZXR3ZCgiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YS8iKQoKc2V0LnNlZWQoMSkKYGBgCgoKCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0RGF0YSkKbGlicmFyeShzY2F0ZXIpCmxpYnJhcnkoemVsbGtvbnZlcnRlcikKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKbGlicmFyeShFbnNEYi5NbXVzY3VsdXMudjc5KQpsaWJyYXJ5KFNpZ25hYykKfSkKYGBgCgojIE1vdXNlIGdhc3RydWxhdGlvbiBkYXlzIEU3LjUsIEU4LjAsIEU4LjUsIEU4Ljc1CgpUaGUgZGF0YXNldCBjb25zaXN0cyBvZiBtdWx0aW9tZSBkYXRhIChzY0FUQUMtc2VxICYgc2NSTkEtc2VxKSBmcm9tIGNlbGxzIGF0IHRoZSAKZm91ciBtZW50aW9uZWQgdGltZXBvaW50cy4KCldlIGNhbiByZWFkIGluIHRoZSAuaDVhZCBmaWxlIGFzIGEgU3VtbWFyaXplZENlbGxFeHBlcmltZW50CgpgYGB7cn0Kcm5hX2dhc3RyX1NFIDwtIHJlYWRINUFEKCJqdXB5dGVyX25vdGVib29rcy9hbm5kYXRhX3JuYS5oNWFkIikKYXRhY19nYXN0cl9TRSA8LSByZWFkSDVBRCgianVweXRlcl9ub3RlYm9va3MvYW5uZGF0YV9hdGFjX3BlYWtfbWF0cml4Lmg1YWQiKQoKcHJpbnQocGFzdGUwKCJUaGUgUk5BIGRhdGEgaGFzIGRpbWVuc2lvbnMgIiwgcGFzdGUoZGltKHJuYV9nYXN0cl9TRSksIGNvbGxhcHNlID0gIiwgIikpKQpwcmludChwYXN0ZTAoIlRoZSBBVEFDIGRhdGEgaGFzIGRpbWVuc2lvbnMgIiwgcGFzdGUoZGltKGF0YWNfZ2FzdHJfU0UpLCBjb2xsYXBzZSA9ICIsICIpKSkKYGBgCgoKV2UgY2FuIGNvbnZlcnQgU3VtbWFyaXplZENlbGxFeHBlcmltZW50IHRvIGEgU2V1cmF0IG9iamVjdC4gVGhlIFN1bW1hcml6ZWRFeHBlcmltZW50CmNvbnRhaW5zIHRoZSByYXcgY291bnRzIG9mIHRoZSBnZW5lIGV4cHJlc3Npb24uIEFkZGl0aW9uYWxseSB3ZSBjYW4gYWRkIHRoZQptZXRhZGF0YSBpbmZvcm1hdGlvbiB0byB0aGUgU2V1cmF0IG9iamVjdHMuCgpgYGB7ciwgcmVzdWx0cyA9ICJhc2lzIn0Kcm5hX3NldXJhdCA8LSBhcy5TZXVyYXQocm5hX2dhc3RyX1NFLCBjb3VudHMgPSAiWCIsIGRhdGEgPSAiWCIpCmF0YWNfc2V1cmF0IDwtIGFzLlNldXJhdChhdGFjX2dhc3RyX1NFLCBjb3VudHMgPSAiWCIsIGRhdGEgPSAiWCIpCgojIExldHMgYWRkIHRoZSBtZXRhZGF0YSB0byB0aGUgU2V1cmF0IG9iamVjdApybmFfc2V1cmF0IDwtIEFkZE1ldGFEYXRhKHJuYV9zZXVyYXQsIGFzLmRhdGEuZnJhbWUoY29sRGF0YShybmFfZ2FzdHJfU0UpKSkKYXRhY19zZXVyYXQgPC0gQWRkTWV0YURhdGEoYXRhY19zZXVyYXQsIGFzLmRhdGEuZnJhbWUoY29sRGF0YShhdGFjX2dhc3RyX1NFKSkpCnJuYV9zZXVyYXQgPC0gQWRkTWV0YURhdGEocm5hX3NldXJhdCwgYXRhY19zZXVyYXRAbWV0YS5kYXRhICU+JSBkcGx5cjo6c2VsZWN0KEJsYWNrbGlzdFJhdGlvOkZSSVApKQoKCnJuYV9zZXVyYXRAbWV0YS5kYXRhICU+JSBoZWFkICU+JSBrbml0cjo6a2FibGUoKQphdGFjX3NldXJhdEBtZXRhLmRhdGEgJT4lIGhlYWQgJT4lIGtuaXRyOjprYWJsZSgpCmBgYAoKCiMgc2NSTkEtc2VxCgojIyBRQwoKCiMjIyBFbXB0eSBEcm9wbGV0cwoKYGBge3J9Cgp0aWJibGUoc2FtcGxlID0gcm5hX3NldXJhdEBtZXRhLmRhdGEkc2FtcGxlLCB1bWlfcGVyX2NlbGwgPSBNYXRyaXg6OmNvbFN1bXMocm5hX3NldXJhdEBhc3NheXMkb3JpZ2luYWxleHAgQGNvdW50cykpICU+JSAKICBhcnJhbmdlKHNhbXBsZSwgZGVzYyh1bWlfcGVyX2NlbGwpKSAlPiUgCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgCiAgbXV0YXRlKGlkeCA9IHNlcV9hbG9uZyhzYW1wbGUpKSAlPiUgCiAgbXV0YXRlKGN1bV91bWlfcGVyX2NlbGwgPSBjdW1zdW0odW1pX3Blcl9jZWxsKSkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSBpZHgsIHkgPSBjdW1fdW1pX3Blcl9jZWxsKSkgKwogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZpeGVkIikgKwogIHNjYWxlX3lfbG9nMTAoKSArIHNjYWxlX3hfbG9nMTAoKSArCiAgeWxhYigiY3VtdWxhdGl2ZSBVTUkgY291bnQiKSArCiAgeGxhYigiaW5kZXgiKQoKCmBgYAoKCgpGcm9tIHRoZSBwbG90cyBiZWxvdyBpdCBzZWVtcyB0aGF0IGFsbCBjZWxscyB3aXRoIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCAKZ2VuZXMgYWJvdmUgNDAlIHdlcmUgcmVtb3ZlZC4gVGhlIGVhcmx5IHRpbWUgcG9pbnRzIEU3LjVyZXAxLzIgaGF2ZSB0aGUgaGlnaGVzdApwZXJjZW50YWdlIG9mIG1pdG9jaG9uZHJpYWwgZ2VuZXMuIEVzcGVjaWFsbHkgRTcuNSByZXAyIHNlZW1zIHRvIGhhdmUgYSBoaWdoZXIgCnBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCBnZW5lcy4gQ29udmVyc2VseSwgdGhlIHNhbWUgcmVwbGljYXRlcyBmcm9tIEU3LjUgCmhhdmUgYSBsb3dlciBudW1iZXIgb2YgZmVhdHVyZXMgYW5kIGNvdW50cy4gVGhpcyBtZWFucyB0aGF0IHRoZSBFNy41IHJlcDIgYW5kIHRvCmEgbGVzc2VyIGV4dGVudCBFNy41IHJlcDEgYXJlIG9mIGxvd2VyIHF1YWxpdHkgY29tcGFyZWQgdG8gdGhlIG90aGVyIHNhbXBsZXMuIEU4Ljc1IApyZXAxL3JlcDIgc2VlbSB0byBoYXZlIHRoZSBoaWdoZXN0IHF1YWxpdHkuIAoKCmBgYHtyLCBmaWcud2lkdGg9MTUsIDEwfQojcmVuYW1lIG1ldGFkYXRhCgp2YXJpYWJsZXMgPC0gYygibkZlYXR1cmVfb3JpZ2luYWxleHAiLCAibkNvdW50X29yaWdpbmFsZXhwIiwgIm1pdG9jaG9uZHJpYWxfcGVyY2VudF9STkEiLCAicmlib3NvbWFsX3BlcmNlbnRfUk5BIikKcGxvdHMgPC0gbWFwKHZhcmlhYmxlcywgZnVuY3Rpb24obil7CiAgZGYgPC0gcm5hX3NldXJhdEBtZXRhLmRhdGEKICBnZ3Bsb3QoZGYpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGRmICU+JSBwdWxsKCJzYW1wbGUiKSwgeSA9IGRmICU+JSBwdWxsKG4pLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gZGYgJT4lIHB1bGwoInNhbXBsZSIpKSwgYWxwaGEgPSAuMSkgKwogICAgZ2VvbV92aW9saW4oYWVzKHggPSBkZiAlPiUgcHVsbCgic2FtcGxlIiksIHkgPSBkZiAlPiUgcHVsbChuKSwKICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGRmICU+JSBwdWxsKCJzYW1wbGUiKSksIGFscGhhID0gLjUpICsKICAgIHhsYWIoInNhbXBsZSIpICsKICAgIHlsYWIocGFzdGUwKG4pKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG4pKSArCiAgICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9InNhbXBsZSIpKQp9KQoKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoZ3JvYnMgPSBwbG90cywgbmNvbCA9IDIpCgpgYGAKCiMjIEhvdyBnb29kIGFyZSB0aGUgYW5ub3RhdGlvbnM/CgpUaGVyZSBhcmUgdHdvIGRpZmZlcmVudCBtZXRob2RzIGZvciBtYXBwaW5nIGxpc3RlZCBpbiB0aGUgbWV0YWRhdGE6CgoqIFNldXJhdAoqIE1OTgoKYGBge3J9CmF0YWNfc2V1cmF0QG1ldGEuZGF0YSAlPiUgZ3JvdXBfYnkoY2VsbHR5cGUubWFwcGVkX3NldXJhdCkgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUga25pdHI6OmthYmxlKGNhcHRpb24gPSAiTnVtYmVyIG9mIGNlbGx0eXBlcyB1c2luZyBTZXVyYXQiKQoKYXRhY19zZXVyYXRAbWV0YS5kYXRhICU+JSBncm91cF9ieShjZWxsdHlwZS5tYXBwZWRfbW5uKSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSBrbml0cjo6a2FibGUoY2FwdGlvbiA9ICJOdW1iZXIgb2YgY2VsbHR5cGVzIHVzaW5nIE1OTiIpCmBgYAoKCgpUaGUgYW5ub3RhdGlvbnMgYXJlIHNpbWlsYXIgYWNyb3NzIHRoZSBkaWZmZXJlbnQgc2FtcGxlcy4gSG93ZXZlciwgdGhlcmUgYXJlCnNvbWUgZGlmZmVyZW5jZXMgaW4gdGhlIGNvbmZpZGVuY2Ugd2l0aCB3aGljaCBjZWxscyBjYW4gbWUgbWFwcGVkIGZvciBkaWZmZXJlbnQKY2VsbHR5cGVzLiBGb3IgZXhhbXBsZSwgY2FyZGlvbXlvY3l0ZXMsIGVyeXRocm9pZHMgYW5kIGV4dHJhZW1icnlvbmljIGVjdG9kZXJtCmFuZCBlbmRvZGVybSAoYnV0IG5vdCBtZXNvZGVybSksIG1lc2VuY2h5bWUgYW5kIHBhcmlldGFsIGVuZG9kZXJtIGNhbiBiZSBtYXBwZWQKd2l0aCB2ZXJ5IGhpZ2ggY29uZmlkZW5jZS4gCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0KYXRhY19zZXVyYXRAbWV0YS5kYXRhICU+JSAKICBnZ3Bsb3QoKSArIAogIGdlb21fYm94cGxvdChhZXMoeCA9IGNlbGx0eXBlLm1hcHBlZF9zZXVyYXQsIHkgPSAgY2VsbHR5cGUuc2NvcmVfc2V1cmF0LCBmaWxsID0gY2VsbHR5cGUubWFwcGVkX3NldXJhdCkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuOCwgaGp1c3Q9MSkpICsgTm9MZWdlbmQoKQoKCmF0YWNfc2V1cmF0QG1ldGEuZGF0YSAlPiUgCiAgZ2dwbG90KCkgKyAKICBnZW9tX2JveHBsb3QoYWVzKHggPSBjZWxsdHlwZS5tYXBwZWRfbW5uLCB5ID0gIGNlbGx0eXBlLnNjb3JlX21ubiwgZmlsbCA9IGNlbGx0eXBlLm1hcHBlZF9tbm4pKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjgsIGhqdXN0PTEpKSArIE5vTGVnZW5kKCkKYGBgCgoKIyMgTm9ybWFsaXplICYgU2NhbGUKCmBgYHtyfQpybmFfc2V1cmF0IDwtIHJuYV9zZXVyYXQgJT4lIAogIE5vcm1hbGl6ZURhdGEodmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgU2NhbGVEYXRhKHZlcmJvc2UgPSBGQUxTRSkgJT4lCiAgRmluZFZhcmlhYmxlRmVhdHVyZXModmVyYm9zZSA9IEZBTFNFKQoKCiNnYXN0cl9zZXVyYXRAYXNzYXlzJFJOQUBkYXRhWzA6MTAsIDA6MTBdCmBgYAoKCiMjIyBQQ0EKCkkgd2lsbCBwcm9jZWVkIHdpdGggMTUgUENzLgoKYGBge3J9CnJuYV9zZXVyYXQgPC0gUnVuUENBKHJuYV9zZXVyYXQsIGZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhybmFfc2V1cmF0KSwKICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKCkVsYm93UGxvdChybmFfc2V1cmF0KQpgYGAKCmBgYHtyfQpwY2FfcGxvdHMgPC0gY29tcHJlaGVucjo6dG9fbGlzdChmb3IgKGkgaW4gMToxNSkKICBEaW1QbG90KHJuYV9zZXVyYXQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gaTooaSsxKSkgKwogICAgdGhlbWUoKSkKCiNwY2FfcGxvdHMKI2dyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKHVubGlzdChwY2FfcGxvdHMpLCBuY29sID0gMywgbnJvdyA9IDUpCgpgYGAKCiMjIENsdXN0ZXJpbmcKClRyeWluZyBhIGRpZmZlcmVudCByZXNvbHV0aW9uIGZvciB0aGUgY2x1c3RlcmluZyB0byBzZWUgaWYgdGhlIE1lc2VuY2h5bWUgd2lsbCAKc3RpbGwgc2VwYXJhdGUuCgpgYGB7cn0Kcm5hX3NldXJhdCA8LSBGaW5kTmVpZ2hib3JzKHJuYV9zZXVyYXQsIHZlcmJvc2UgPSBGQUxTRSkKcm5hX3NldXJhdCA8LSBGaW5kQ2x1c3RlcnMocm5hX3NldXJhdCwgdmVyYm9zZSA9IEZBTFNFLCByZXNvbHV0aW9uID0gMC42KQpybmFfc2V1cmF0IDwtIFJ1blVNQVAocm5hX3NldXJhdCwgdmVyYm9zZSA9IEZBTFNFLCBkaW1zID0gMToxNSkKYGBgCgoKIyMgVmlzdWFsaXphdGlvbgoKYGBge3J9CmNvbFBhbGV0dGVfY2VsbHR5cGVzID0gYygnIzUzMkM4QScsCiAnI2MxOWY3MCcsCiAnI2Y5ZGVjZicsCiAnI2M5YTk5NycsCiAnI0I1MUQ4RCcsCiAnIzNGODRBQScsCiAnIzllNjc2MicsCiAnIzM1NEUyMycsCiAnI0YzOTdDMCcsCiAnI2ZmODkxYycsCiAnIzYzNTU0NycsCiAnI0M3MjIyOCcsCiAnI2Y3OTA4MycsCiAnI0VGNEUyMicsCiAnIzk4OTg5OCcsCiAnIzdGNjg3NCcsCiAnIzg4NzBhZCcsCiAnIzY0N2E0ZicsCiAnI0VGNUE5RCcsCiAnI0ZCQkU5MicsCiAnIzEzOTk5MicsCiAnI2NjNzgxOCcsCiAnI0RGQ0RFNCcsCiAnIzhFQzc5MicsCiAnI0M1OTRCRicsCiAnI0MzQzM4OCcsCiAnIzBGNEE5QycsCiAnI0ZBQ0IxMicsCiAnIzhEQjVDRScsCiAnIzFBMUExQScsCiAnI0M5RUJGQicsCiAnI0RBQkU5OScsCiAnIzY1QTgzRScsCiAnIzAwNTU3OScsCiAnI0NERTA4OCcsCiAnI2Y3Zjc5ZScsCiAnI0Y2QkZDQicpCmBgYAoKClRoZXJlIGFyZSB0d28gcG9zc2liaWxpdGllcyB0byBwcm9jZWVkIHdpdGggY2VsbHR5cGUgYW5ub3RhdGlvbnM6CgoqIFNldXJhdCAodGhpcyBpcyB0aGUgb25lIEkgdXNlZCkKKiBNTk4KCkluIHRoZSBwbG90IGJlbG93IHlvdSBjYW4gc2VlIHRoYXQgdGhlIE1lc2VuY2h5bWUgc2VwYXJhdGVzIGludG8gdHdvIGNsdXN0ZXJzLCAKZXZlbiB0aG91Z2ggdGhlIGNlbGxzIGJlbG9uZyB0byB0aGUgc2FtZSBjZWxsdHlwZS4gVGhlcmVmb3JlIEkgdmlzdWFsaXplZCB0aGUgCk1lc2VuY2h5bWUgY2VsbHMgYWNjb3JkaW5nIHRvIHRoZWlyIHJlc3BlY3RpdmUgdGltZSBwb2ludCBhbmQgcmVwbGljYXRlIGJlbG93LiBJdCAKYmVjb21lcyBldmlkZW50IHRoYXQgdGhlIE1lc2VuY2h5bWUgc2VwYXJhdGUgaW50byBFNy41IGFuZCBFOC4wLCBFOC41LCBFOC43NS4gVGhlcmVmb3JlLAp0aGUgc2VwYXJhdGlvbiBpcyBwcm9iYWJseSBhIGJpb2xvZ2ljYWwgZWZmZWN0IGNvcnJlc3BvbmRpbmcgdG8gZGlmZmVyZW50IHNpZ25hdHVyZXMgCmF0IGRpZmZlcmVudCB0aW1lIHBvaW50cy4gSG93ZXZlciwgd2Ugc2hvdWxkIGtlZXAgaW4gbWluZCB0aGF0IEU3LjUgd2FzIGFsc28gdGhlCnRpbWUgcG9pbnQgd2l0aCBsb3dlc3QgcXVhbGl0eSBvZiBjZWxscy4gCgpUaGVyZSBpcyBvbmUgY2x1c3RlciB3aGljaCBjb250YWlucyBhIHZlcnkgaGV0ZXJvZ2VuZW91cyBwb3B1bGF0aW9uIG9mIGNlbGxzLApuYW1lbHkgbWl4ZWQgJiBuYXNjZW50IG1lc29kZXJtLCBjYXVkYWwgJiByb3N0cmFsIG5ldXJvZWN0b2Rlcm0sIHByaW1pdGl2ZSBzdHJlYWssIApjYXVkYWwgZXBpYmxhc3QgYW5kIGVwaWJsYXN0LiBBcyB3ZSB3aWxsIHNlZSBsYXRlciBvbiwgdGhlc2UgYXJlIHByaW1hcmlseSBlYXJseSBjZWxsdHlwZXMKZm91bmQgYXQgRTcuNSwgd2hpY2ggYXJlIG5vdCBwcmVzZW50IGF0IGxhdGVyIHRpbWVwb2ludHMgYW55bW9yZS4KCmBgYHtyfQpjZWxsdHlwZXMgPC0gKGF0YWNfc2V1cmF0QG1ldGEuZGF0YSAlPiUgZ3JvdXBfYnkoY2VsbHR5cGUubWFwcGVkX3NldXJhdCkgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSkkY2VsbHR5cGUubWFwcGVkX3NldXJhdAoKY29sIDwtIHNldE5hbWVzKGNvbFBhbGV0dGVfY2VsbHR5cGVzLCBjZWxsdHlwZXMpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQgPSAxMH0KRGltUGxvdChybmFfc2V1cmF0LCByZWR1Y3Rpb24gPSAidW1hcCIsIHB0LnNpemUgPSAxLCAKICAgICAgICBncm91cC5ieSA9ICJjZWxsdHlwZS5tYXBwZWRfc2V1cmF0IiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGNvbHMgPSBjb2wpICsKICBOb0xlZ2VuZCgpCmBgYAoKYGBge3J9CkRpbVBsb3Qoc3Vic2V0KHJuYV9zZXVyYXQsIGNlbGx0eXBlLm1hcHBlZF9zZXVyYXQgPT0gIk1lc2VuY2h5bWUiKSwgCiAgICAgICAgZ3JvdXAuYnkgPSAic2FtcGxlIikKRGltUGxvdChzdWJzZXQocm5hX3NldXJhdCwgY2VsbHR5cGUubWFwcGVkX3NldXJhdCA9PSAiTWVzZW5jaHltZSIpLCAKICAgICAgICBzcGxpdC5ieSAgPSAic2FtcGxlIikKYGBgCgpQbG90IHdpdGggY29sb3IgbGVnZW5kLgoKYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodCA9IDEwfQpEaW1QbG90KHJuYV9zZXVyYXQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgcHQuc2l6ZSA9IDEsIAogICAgICAgIGdyb3VwLmJ5ID0gImNlbGx0eXBlLm1hcHBlZF9zZXVyYXQiLCBjb2xzID0gY29sKSAjLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSkgKwpgYGAKCkNsdXN0ZXJpbmcgYnkgU2V1cmF0IHdpdGggcmVzb2x1dGlvbiA9IDAuNiB5aWVsZHMgMTcgZGlzdGluY3QgY2x1c3RlcnMsIG5vdCBlbm91Z2gKdG8gZGlmZmVyZW50aWF0ZSB0aGUgbGFyZ2UgbnVtYmVyIG9mIGRpZmZlcmVudCBjZWxsdHlwZXMgaW4gdGhpcyBkYXRhc2V0LgoKYGBge3J9CkRpbVBsb3Qocm5hX3NldXJhdCwgcmVkdWN0aW9uID0gInVtYXAiLCBwdC5zaXplID0gLjEsIAogICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gVFJVRSkgKwogIE5vTGVnZW5kKCkKYGBgCgpCZWxvdywgeW91IGNhbiBzZWUgaG93IHRoZSBlYXJsaWVyIHRpbWUgcG9pbnRzIHNlcGFyYXRlIGZyb20gdGhlIGxhdGVyIHRpbWUgCnBvaW50cy4gVGhlIG51bWJlciBvZiBjb3VudHMgaXMgdmVyeSBob21vZ2Vub3VzLCB3aGlsZSB0aGUgbWl0b2Nob25kcmlhbCBSTkEgCnBlcmNlbnRhZ2UgaXMgaGlnaGVyIGFuZCB0aGUgbnVtYmVyIG9mIGZlYXR1cmVzIGxvd2VyIGZvciBFNy41IGFzIGFscmVhZHkgcG9pbnRlZCBvdXQuCgpgYGB7ciwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTEwfQpwMSA8LSBEaW1QbG90KHJuYV9zZXVyYXQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgcHQuc2l6ZSA9IC4xLCBncm91cC5ieSA9ICJzYW1wbGUiKQoKcDIgPC0gRmVhdHVyZVBsb3Qocm5hX3NldXJhdCwgcmVkdWN0aW9uID0gInVtYXAiLCBwdC5zaXplID0gLjEsCiAgICAgICAgICAgIGZlYXR1cmVzID0gIm5Db3VudF9STkEiKSArCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSAKcDMgPC0gRmVhdHVyZVBsb3Qocm5hX3NldXJhdCwgcmVkdWN0aW9uID0gInVtYXAiLCBwdC5zaXplID0gLjEsIGZlYXR1cmVzID0gIm1pdG9jaG9uZHJpYWxfcGVyY2VudF9STkEiKSArCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSAKCnA0IDwtIEZlYXR1cmVQbG90KHJuYV9zZXVyYXQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgcHQuc2l6ZSA9IC4xLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9STkEiKSArCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSAKCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIHA0LCBuY29sID0gMiwgbnJvdyA9IDIpCmBgYAoKCiMjIERpc3RyaWJ1dGlvbiBvZiBjZWxsdHlwZXMgYXQgZGlmZmVyZW50IHRpbWUgcG9pbnRzCgoKVmlzdWFsaXppbmcgdGhlIGNlbGxzIGF0IGVhY2ggdGltZXBvaW50IGluIHNlcGFyYXRlIFVNQVBzIHNob3dzIGhvdyB0aGUKZGlzdHJpYnV0aW9uIG9mIGNlbGx0eXBlcyBjaGFuZ2VzIGFzIGdhc3RydWxhdGlvbiBwcm9jZWVkcy4gVGhlIGhldGVyb2dlbm91cyAKY2VsbCBjbHVzdGVyIHByZXNlbnQgYXQgRTcuNSBkaXNhcHBlYXJzIGF0IGxhdGVyIHRpbWUgcG9pbnRzLiBXZSBjYW4gYWxzbyBzZWUgaG93Cm5vIEVyeXRocm9pZHMgYXJlIHByZXNlbnQgYXQgRTcuNSwKRXJ5dGhyb2lkMSAoYW5kIHRvIGxlc3NlciBleHRlbmQgRXJ5dGhyb2lkMiBhbmQgMykgYXBwZWFyIGF0IEU4LjAsIHdoaWxlIEVyeWh0cm9pZDMgCmFyZSBmb3VuZCB0byBhIGhpZ2hlciBleHRlbnQKYXQgRTguNzUsIHdoaWNoIGluZGljYXRlcyB0aGF0IHRoZXNlIGNlbGxzIGNvcnJlc3BvbmQgdG8gZGlmZmVyZW50IGRldmVsb3BtZW50YWwgCnN0YWdlcy4gCgpgYGB7ciwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTIwfQpEaW1QbG90KHJuYV9zZXVyYXQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgcHQuc2l6ZSA9IDEsIAogICAgICAgIGdyb3VwLmJ5ID0gImNlbGx0eXBlLm1hcHBlZF9zZXVyYXQiLCBzcGxpdC5ieSA9ICJvcmlnLmlkZW50IiwgbmNvbCA9IDEsIGNvbHMgPSBjb2wpICsKICBsYWJzKHRpdGxlID0gIkNlbGx0eXBlcyBhdCBkaWZmZXJlbnQgdGltZSBwb2ludHMiKQpgYGAKCgpXZSBjYW4gc2VlIHRoYXQgbmFzY2VudCBtZXNvZGVybSwgZXBpYmxhc3QgYW5kIHByaW1pdGl2ZSBzdHJlYWsgYXJlIG9ubHkgcHJlc2VudCAKYXQgRTc1LiBBbHNvLCBleHRyYWVtYnJ5b25pY2UgZW5kb2Rlcm0gYW5kIGVjdG9kZXJtIGFyZSBoaWdoZXN0IGFuZCBkZWNyZWFzZSAKd2l0aCBwcm9ncmVzc2luZyBnYXN0cnVsYXRpb24uIEZvcmVicmFpbi9NaWRicmFpbi9IaW5kYnJhaW4sIG5ldXJhbCBjcmVzdCBhbmQgCm5ldXJvbWVzb2Rlcm1hbCBwcm9nZW5pdG9yIChOTVApIGNlbGxzIGFyZSBub3QgcHJlc2VudCBhdCAKRTcuNSwgYnV0IGVtZXJnZSBhdCBFOC4wIGFuZCBhcmUgcHJlc2VudCBhdCBldmVuIGhpZ2hlciBwZXJjZW50YWdlIGF0IEU4LjUuIEFsc28sCnRoZSBlbmRvdGhlbGl1bSBhcHBlYXJzIG9ubHkgYXQgRTguMC4gVGhlIApzYW1lIGlzIHRydWUgZm9yIEFsbGFudG9pcywgZXJ5dGhyb2lkcyAocHJvZHVjZSByZWQgYmxvb2QgY2VsbHMsIHJlbWFpbiBpbiBib25lCm1hcnJvdylhbmQgY2FyZGlvbXlvY3l0ZXMuICBDb252ZXJzZWx5LCB0aGUgbnVtYmVyCm9mIGV4dHJhZW1icnlvbmljIGVjdG9kZXJtIGNlbGxzIGFuZCBleHRyYWVtYnJ5b25pYyBlbmRvZGVybSBjZWxscyBiZWNvbWUgbGVzcyAKYXQgZWFjaCB0aW1lIHN0ZXAuIAoKKFBpanVhbl9TYWxhIGV0LmFsLCBBIHNpbmdsZS1jZWxsIG1vbGVjdWxhciBtYXAgb2YgbW91c2UKZ2FzdHJ1bGF0aW9uIGFuZCBlYXJseSBvcmdhbm9nZW5lc2lzLCAyMDE5LCBOYXR1cmUpCgpgYGB7ciwgZmlnLndpZHRoPTEwfQojIHBsb3QgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIGNlbGwgdHlwZSBhdCBlYWNoIGVtYnJ5b25pYyBzdGFnZQojIGFsbCBmcmVxdWVuY2llcyBmb3Igb25lIGVtYnJ5b25pYyBzdGFnZSB3b3VsZCBhZGQgdXAgdG8gMApybmFfc2V1cmF0QG1ldGEuZGF0YSAlPiUKICBncm91cF9ieShvcmlnLmlkZW50LCBjZWxsdHlwZS5tYXBwZWRfc2V1cmF0KSAlPiUgCiAgc3VtbWFyaXNlKFRvdGFsID0gbigpKSAlPiUgCiAgbXV0YXRlKGZyZXEgPSBUb3RhbC9zdW0oVG90YWwpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY2VsbHR5cGUubWFwcGVkX3NldXJhdCwgeSA9IGZyZXEsIGZpbGwgPSBvcmlnLmlkZW50KSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDAuOCwgaGp1c3Q9MSkpIAogIApgYGAKCgojIyBQcm9jZXNzaW5nIERhdGEgYXQgZWFjaCB0aW1lIHN0ZXAgc2VwYXJhdGVseQoKV2hlbiBkb2luZyB0aGUgcHJlcHJvY2Vzc2luZyBzdGVwcyBhbmQgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIGZvciBlYWNoIAp0aW1lIHBvaW50IHNlcGFyYXRlbHksIHdlIGNhbiBjcmVhdGUgbW9yZSBjbGVhcmx5IHNlcGFyYXRlZCBjbHVzdGVycyBmb3IgdGhlCmxhdGVyIHRpbWUgcG9pbnRzLCBob3dldmVyLCBmb3IgRTcuNSB0aGUgbWl4ZWQgY2x1c3RlciBvZiBlcGlibGFzdCwgbWl4ZWQgJiBuYXNjZW50Cm1lc29kZXJtLCBwcmltaXRpdmUgc3RyZWFrIGFuZCBQR0MgcmVtYWlucyBhIGhldGVyb2dlbmVvdXMgY2x1c3Rlci4gCgpgYGB7cn0Kc3RhZ2VzIDwtIGMoIkU3LjUiLCAiRTguMCIsICJFOC41IiwgIkU4Ljc1IikKc2V1cmF0X29iamVjdHMgPC0gbWFwKHN0YWdlcywgZnVuY3Rpb24obil7CiAgcm5hX3NldXJhdCA8LSBzdWJzZXQocm5hX3NldXJhdCwgc3Vic2V0ID0gb3JpZy5pZGVudCA9PSBuKQogIHJuYV9zZXVyYXQgPC0gcm5hX3NldXJhdCAgJT4lIAogICAgTm9ybWFsaXplRGF0YSh2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgIFNjYWxlRGF0YSh2ZXJib3NlID0gRkFMU0UpICU+JQogICAgRmluZFZhcmlhYmxlRmVhdHVyZXModmVyYm9zZSA9IEZBTFNFKSAKICBybmFfc2V1cmF0IDwtIHJuYV9zZXVyYXQgJT4lICBSdW5QQ0EoZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKHJuYV9zZXVyYXQpLCB2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgIEZpbmROZWlnaGJvcnModmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICBGaW5kQ2x1c3RlcnModmVyYm9zZSA9IEZBTFNFLCByZXNvbHV0aW9uID0gLjkpICU+JSAKICAgIFJ1blVNQVAodmVyYm9zZSA9IFRSVUUsIGRpbXMgPSAxOjE1KQogIGxpc3QobmFtZSA9IG4sIG9iamVjdCA9IHJuYV9zZXVyYXQpCiAgICAKfSkKCgplNzUgPC0gc2V1cmF0X29iamVjdHNbWzFdXSRvYmplY3QKZTgwIDwtIHNldXJhdF9vYmplY3RzW1syXV0kb2JqZWN0CmU4NSA8LSBzZXVyYXRfb2JqZWN0c1tbM11dJG9iamVjdAplNzg1IDwtIHNldXJhdF9vYmplY3RzW1s0XV0kb2JqZWN0CmBgYAoKCgpgYGB7ciwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTIwfQpwbG90cyA8LSBtYXAoc2VxLmludCgxLDQpLCBmdW5jdGlvbihuKXsKICBvYmplY3QgPC0gc2V1cmF0X29iamVjdHNbW25dXSRvYmplY3QKICBwMSA8LSBEaW1QbG90KG9iamVjdCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJjZWxsdHlwZS5tYXBwZWRfc2V1cmF0IiwgCiAgICAgICAgICAgICAgICBjb2xzID0gY29sLCBzaXplID0gLjkpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAoc2V1cmF0X29iamVjdHNbW25dXSRuYW1lLCAiIGNlbGx0eXBlcyIpKQogIGxpc3QocGxvdCA9IHAxKQp9KQoKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocGxvdHNbWzFdXSRwLCBwbG90c1tbMl1dJHAsIHBsb3RzW1szXV0kcCxwbG90c1tbNF1dJHAsIG5jb2wgPSAxKQpgYGAKCgoKIyBzY0FUQUMtc2VxIGRhdGEKCgojIyBRQyBBVEFDCgpgYGB7cn0KYXRhY19zZXVyYXRAbWV0YS5kYXRhICU+JQogIGdncGxvdCgpICsKICBnZW9tX2RlbnNpdHkyZF9maWxsZWQoYWVzKHg9bG9nMTAobkZyYWdzX2F0YWMgKSwgeT1UU1NFbnJpY2htZW50X2F0YWMpLCBiaW5zPTIwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNSwgY29sb3I9ImdyZWVuIiwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAzLCBjb2xvcj0iZ3JlZW4iLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICNnZW9tX3hzaWRlZGVuc2l0eShhZXMoeD1sb2cxMChwcmVfZmlsdGVyX21ldGEkbkZyYWdzKSkpICsKICAjZ2VvbV95c2lkZWRlbnNpdHkoYWVzKHkgPSBwcmVfZmlsdGVyX21ldGEkVFNTRW5yaWNobWVudCkpICsKICBmYWNldF93cmFwKH5zYW1wbGUpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHggPSAiTG9nMTAgVW5pcXVlIEZyYWdtZW50cyIsIHkgPSAiVFNTIEVucmljaG1lbnQgU2NvcmUiKQpgYGAKClRoZSBzY0FUQUMtc2VxIHNob3dzIHRoYXQgRTcuNSBzZWVtcyB0byBiZSBvZiBsb3dlciBxdWFsaXR5LCB3aGljaCB3ZSBoYXZlIGFscmVhZHkKb2JzZXJ2ZWQgaW4gdGhlIHNjUk5BLXNlcS4gUG90ZW50aWFsbHksIHRoZSBjZWxscyB3aGVyZSBzaW1wbHkgaW4gYSB3b3JzZSAKY29uZGl0aW9uIHdoZW4gc2VxdWVuY2VkLgoKYGBge3IsIGZpZy53aWR0aD0xMH0KcDEgPC0gYXRhY19zZXVyYXRAbWV0YS5kYXRhICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2dyaWRnZXM6Omdlb21fZGVuc2l0eV9yaWRnZXMoYWVzKHggPSBUU1NFbnJpY2htZW50LCB5ID0gU2FtcGxlLCBmaWxsID0gU2FtcGxlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC42KQoKcDIgPC0gYXRhY19zZXVyYXRAbWV0YS5kYXRhICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBTYW1wbGUsIHkgPSBUU1NFbnJpY2htZW50LCBmaWxsID0gU2FtcGxlKSwgYWxwaGEgPSAwLjYpICsKICBnZW9tX2JveHBsb3QoYWVzKHggPSBTYW1wbGUsIHkgPSBUU1NFbnJpY2htZW50LGZpbGwgPSBTYW1wbGUpLCBhbHBoYSA9IDAuMSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlRTUyBFbnJpY2htZW50IikKY293cGxvdDo6cGxvdF9ncmlkKHAyLCBwMSwgbmNvbCA9IDIpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTB9CnAxIDwtIGF0YWNfc2V1cmF0QG1ldGEuZGF0YSAlPiUgCiAgZ2dwbG90KCkgKwogIGdncmlkZ2VzOjpnZW9tX2RlbnNpdHlfcmlkZ2VzKGFlcyh4ID0gbkZyYWdzX2F0YWMgLCB5ID0gU2FtcGxlLCBmaWxsID0gU2FtcGxlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC42KQoKcDIgPC0gYXRhY19zZXVyYXRAbWV0YS5kYXRhICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBTYW1wbGUsIHkgPSBuRnJhZ3NfYXRhYyAsIGZpbGwgPSBTYW1wbGUpLCBhbHBoYSA9IDAuNikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IFNhbXBsZSwgeSA9IG5GcmFnc19hdGFjICxmaWxsID0gU2FtcGxlKSwgYWxwaGEgPSAwLjEpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJUU1MgRW5yaWNobWVudCIpCmNvd3Bsb3Q6OnBsb3RfZ3JpZChwMiwgcDEsIG5jb2wgPSAyKQpgYGAKCiMjIE5vcm1hbGl6YXRpb24gJiBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gQVRBQwoKKipMYXRlbnQgU2VtYW50aWMgSW5kZXhpbmcqKgoKMS4gVEYtSURGIG5vcm1hbGl6YXRpb24KICArIG5vcm1hbGl6ZSBhY3Jvc3MgY2VsbHMgKHNlcXVlbmNpbmcgZGVwdGgpCiAgKyBub3JtYWxpemUgYWNyb3NzIHBlYWsgKGhpZ2hlciB2YWx1ZXMgdG8gbW9yZSByYXJlIHBlYWtzKQoyLiBTZWxlY3QgVG9wIGZlYXR1cmVzCjMuICBSdW4gU1ZEIG9uIHNlbGVjdGVkIGZlYXR1cmVzCgpgYGB7cn0KYXRhY19zZXVyYXQgPC0gUnVuVEZJREYoYXRhY19zZXVyYXQpCmF0YWNfc2V1cmF0IDwtIEZpbmRUb3BGZWF0dXJlcyhhdGFjX3NldXJhdCkKYXRhY19zZXVyYXQgPC0gUnVuU1ZEKGF0YWNfc2V1cmF0KQpgYGAKVGhlIGZpcnN0IExTSSBjb21wb25lbnQgb2Z0ZW4gY2FwdHVyZXMgc2VxdWVuY2luZyBkZXB0aC4gV2Ugd2lsbAp0aGVyZWZvcmUgcmVtb3ZlIGl0IGZyb20gZG93bnN0cmVhbSBhbmFseXNpcy4gVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gc2VxdWVuY2luZwpkZXB0aCBhbmQgZWFjaCBMU0kgY29tcG9uZW50IGlzIHNob3duIGluIHRoZSBwbG90IGJlbG93LgoKYGBge3J9CkRlcHRoQ29yKGF0YWNfc2V1cmF0KQpgYGAKCiMjIFZpc3VhbGl6YXRpb24KCmBgYHtyfQphdGFjX3NldXJhdCA8LSBSdW5VTUFQKGF0YWNfc2V1cmF0LCByZWR1Y3Rpb24gPSAibHNpIiwgZGltcyA9IDI6MzAsIHZlcmJvc2UgPSBGQUxTRSkKYWF0YWNfc2V1cmF0IDwtIEZpbmROZWlnaGJvcnMoYXRhY19zZXVyYXQsIHJlZHVjdGlvbiA9ICJsc2kiLCBkaW1zID0gMjozMCwgdmVyYm9zZSA9IEZBTFNFKQoKIyBmb3IgQ2xzdXRlcmluZyBpbnN0ZWFkIG9mIExvdXZpYW4gU0xNIGFsZ29yaXRobSBpcyB1c2VkCiNhdGFjX3NldXJhdCA8LSBGaW5kQ2x1c3RlcnMoYXRhY19zZXVyYXQsIHZlcmJvc2UgPSBGQUxTRSwgYWxnb3JpdGhtID0gMykgCmBgYAoKCgpgYGB7ciwgZmlnLndpZHRoID0gMTUsIGZpZy5oZWlnaHQ9MTB9CgpEaW1QbG90KGF0YWNfc2V1cmF0LCBncm91cC5ieSA9ICJjZWxsdHlwZS5tYXBwZWRfc2V1cmF0IiwgcmVkdWN0aW9uID0gInVtYXAiLCBwdC5zaXplID0gMSwgY29scyA9IGNvbCkgKwogIGxhYnModGl0bGUgPSAic2NBVEFDLXNlcSBDZWxsdHlwZSIpCiAgCkRpbVBsb3QoYXRhY19zZXVyYXQsIGdyb3VwLmJ5ID0gInNhbXBsZSIsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgcHQuc2l6ZSA9IDEsIGNvbHMgPSBjb2wpICsKICBsYWJzKHRpdGxlID0gInNjQVRBQy1zZXEgQ2VsbHR5cGUiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTB9CkRpbVBsb3Qocm5hX3NldXJhdCAsIGdyb3VwLmJ5ID0gImNlbGx0eXBlLm1hcHBlZF9zZXVyYXQiLCBwdC5zaXplID0gMSwgY29scyA9IGNvbCwKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIpICsKICBsYWJzKHRpdGxlID0gInNjUk5BLXNlcSBDZWxsdHlwZSIpCgpgYGAKCgpMZXRzIGhhdmUgYSBsb29rIGF0IHdoZXRoZXIgdGhlIG51bWJlciBvZiBmcmFnbWVudHMgaXMgY29ycmVsYXRlZCB0byB0aGUgCm51bWJlciBvZiBjb3VudHMgaW4gZWFjaCBjZWxsdHlwZS4gVGhpcyBzZWVtcyB0byBiZSB0aGUgY2FzZS4KCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CmF0YWNfc2V1cmF0QG1ldGEuZGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9nMTAobkNvdW50X29yaWdpbmFsZXhwICksIHkgPSBsb2cxMChuRnJhZ3NfYXRhYykpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IC4yLCBzaXplID0gLjIpICsKICBnZ3NpZGU6Omdlb21feHNpZGVkZW5zaXR5KCkgKwogIGdnc2lkZTo6Z2VvbV95c2lkZWRlbnNpdHkoKSArCiAgZmFjZXRfd3JhcCh+c2FtcGxlKSArCiAgbGFicyh4ID0gIkxvZzEwIENvdW50cyIsIHkgPSAibG9nMTAgVW5pcXVlIEZyYWdtZW50cyIpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmF0YWNfc2V1cmF0QG1ldGEuZGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9nMTAobkNvdW50X29yaWdpbmFsZXhwKSwgeSA9IGxvZzEwKFRTU0VucmljaG1lbnQpKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC4yLCBhbHBoYSA9IC4yKSArCiAgZ2dzaWRlOjpnZW9tX3hzaWRlZGVuc2l0eSgpICsKICBnZ3NpZGU6Omdlb21feXNpZGVkZW5zaXR5KCkgKwogIGZhY2V0X3dyYXAofnNhbXBsZSkKYGBgCgoKYGBge3J9CmF0YWNfc2V1cmF0QG1ldGEuZGF0YSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gUHJvbW90ZXJSYXRpb19hdGFjKSkgCgphdGFjX3NldXJhdEBtZXRhLmRhdGEgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IE51Y2xlb3NvbWVSYXRpb19hdGFjKSkgCmBgYAoKCgpgYGB7cn0Kc2F2ZVJEUyhhdGFjX3NldXJhdCwgImF0YWNfU2V1cmF0X29iamVjdCIpCnNhdmVSRFMocm5hX3NldXJhdCwgInJuYV9TZXVyYXRfb2JqZWN0IikKYGBgCgoK